import { Loading, Dialog } from 'quasar';
import { FirebaseError } from 'firebase/app';
import {
  getAuth,
  createUserWithEmailAndPassword,
  signInWithEmailAndPassword,
  GoogleAuthProvider,
  FacebookAuthProvider,
  TwitterAuthProvider,
  OAuthProvider,
  signInWithPopup,
  signOut as SignOut,
  AuthErrorCodes,
  Auth,
  fetchSignInMethodsForEmail,
  linkWithCredential,
} from 'firebase/auth';

function getProvider(providerId: string) {
  switch (providerId) {
    case GoogleAuthProvider.PROVIDER_ID:
      return new GoogleAuthProvider();
    case FacebookAuthProvider.PROVIDER_ID:
      return new FacebookAuthProvider();
    case TwitterAuthProvider.PROVIDER_ID:
      return new TwitterAuthProvider();
    case 'microsoft.com':
      return new OAuthProvider('microsoft.com');
    default:
      throw new Error(`No provider implemented for ${providerId}`);
  }
}
async function handleAccountExistsError(
  auth: Auth,
  email: string,
  _credential: any
): Promise<IUserInfo | null> {
  if (!email) {
    console.error('error with handleAccountExistsError: no email address');
    return null;
  }
  const pendingCred = _credential;
  const methods = await fetchSignInMethodsForEmail(auth, email);
  if (methods[0] === 'password') {
    // TODO popup a dialog for user password;
    return null;
  }
  const provider = getProvider(methods[0]);
  provider.setCustomParameters({
    login_hint: email,
  });

  const result = await signInWithPopup(auth, provider);
  if (result) {
    const userCredential = await linkWithCredential(result.user, pendingCred);
    const userInfo: IUserInfo = {
      avatar: userCredential.user.photoURL,
      username: userCredential.user.displayName,
      email: userCredential.user.email,
      uid: userCredential.user.uid,
    };
    return userInfo;
  } else {
    return null;
  }
}
export function createUserWithEmail(
  email: string,
  password: string
): Promise<any> {
  return new Promise(async (resovle, reject) => {
    const auth = getAuth();
    const userCredential = await createUserWithEmailAndPassword(
      auth,
      email,
      password
    ).catch((error) => {
      throw error;
    });
    console.log(userCredential.user);
    // TODO
    // 发送验证邮件，验证成功后继续登录
  });
}
export function signinWithEmail(email: string, password: string) {
  return new Promise(async (resovle, reject) => {
    const auth = getAuth();
    const userCredential = await signInWithEmailAndPassword(
      auth,
      email,
      password
    ).catch((error) => {
      throw error;
    });
    console.log(userCredential.user);
    // TODO
    // 检查登录的用户是否验证了邮箱，如果没有，则提示重新发送验证邮件
  });
}
export function google(): Promise<IUserInfo> {
  return new Promise<IUserInfo>(async (resolve, reject) => {
    Loading.show();
    const provider = new GoogleAuthProvider();
    const auth = getAuth();
    const result = await signInWithPopup(auth, provider).catch(
      async (error) => {
        if (error.code === AuthErrorCodes.NEED_CONFIRMATION) {
          const credential = GoogleAuthProvider.credentialFromError(error);
          const user = await handleAccountExistsError(
            auth,
            error.customData!.email as string,
            credential
          );

          if (user) {
            resolve(user);
          } else {
            Dialog.create({
              title: 'Error',
              message: 'Sign in Failed',
            });
          }
          Loading.hide();
          return;
        }
        Dialog.create({
          title: error.code,
          message: error.message,
        });
        reject(error);
        Loading.hide();
        return;
      }
    );
    if (result) {
      const credential = GoogleAuthProvider.credentialFromResult(result);
      const token = credential?.accessToken;
      const user = result.user;
      const final: IUserInfo = {
        username: user.displayName,
        email: user.email,
        avatar: user.photoURL,
        uid: user.uid,
        token: token,
      };
      resolve(final);
      Loading.hide();
    }
    // Loading.show();
    // gapi.load('client:auth2', async () => {
    //   await gapi.client
    //     .init({
    //       apiKey: 'AIzaSyCwfTp6irj42BbX3SO8vH3bk6Bt8b2jRQM',
    //       clientId:
    //         '692741454741-umfiacp5ddgus4p4hs3ua14n2750dlbs.apps.googleusercontent.com',
    //       scope: 'https://www.googleapis.com/auth/profile.emails.read',
    //       discoveryDocs: ['https://people.googleapis.com/$discovery/rest'],
    //     })
    //     .catch((error) => {
    //       Loading.hide();
    //       reject(error);
    //       return null;
    //     });
    //   const auth2 = gapi.auth2.getAuthInstance();
    //   const gUser = await auth2.signIn().catch((error) => {
    //     Loading.hide();
    //     reject(error);
    //     return null;
    //   });
    //   if (gUser && gUser.isSignedIn()) {
    //     const user: IUserInfo = {};
    //     user.username = gUser.getBasicProfile().getName();
    //     user.email = gUser.getBasicProfile().getEmail();
    //     user.avatar = gUser.getBasicProfile().getImageUrl();
    //     user.googleId = gUser.getBasicProfile().getId();
    //     Loading.hide();
    //     resolve(user);
    //   } else {
    //     Loading.hide();
    //     reject(new Error('Login Failed'));
    //   }
    // });
  });
}
export function mslive(): Promise<IUserInfo> {
  return new Promise<IUserInfo>(async (resolve, reject) => {
    Loading.show();
    const provider = new OAuthProvider('microsoft.com');
    const auth = getAuth();
    const result = await signInWithPopup(auth, provider).catch(
      async (error: FirebaseError) => {
        if (error.code === AuthErrorCodes.NEED_CONFIRMATION) {
          const credential = OAuthProvider.credentialFromError(error);
          const user = await handleAccountExistsError(
            auth,
            error.customData!.email as string,
            credential
          );

          if (user) {
            resolve(user);
          } else {
            Dialog.create({
              title: 'Error',
              message: 'Sign in Failed',
            });
          }
          Loading.hide();
          return;
        }
        Dialog.create({
          title: error.code,
          message: error.message,
        });
        reject(error);
        Loading.hide();
        return;
      }
    );
    if (result) {
      const credential = OAuthProvider.credentialFromResult(result);
      const token = credential?.accessToken;
      const user = result.user;
      const final: IUserInfo = {
        username: user.displayName,
        email: user.email,
        avatar: user.photoURL, // TODO can't get user photo in ms live
        uid: user.uid,
        token: token,
      };
      resolve(final);
      Loading.hide();
    }
  });
}
export function facebook(): Promise<IUserInfo> {
  return new Promise<IUserInfo>(async (resolve, reject) => {
    Loading.show();
    const provider = new FacebookAuthProvider();
    const auth = getAuth();
    const result = await signInWithPopup(auth, provider).catch(
      async (error: FirebaseError) => {
        if (error.code === AuthErrorCodes.NEED_CONFIRMATION) {
          const credential = FacebookAuthProvider.credentialFromError(error);
          const user = await handleAccountExistsError(
            auth,
            error.customData!.email as string,
            credential
          );

          if (user) {
            resolve(user);
          } else {
            Dialog.create({
              title: 'Error',
              message: 'Sign in Failed',
            });
          }
          Loading.hide();
          return;
        }
        Dialog.create({
          title: error.code,
          message: error.message,
        });
        reject(error);
        Loading.hide();
        return;
      }
    );
    if (result) {
      const credential = FacebookAuthProvider.credentialFromResult(result);
      const token = credential?.accessToken;
      const user = result.user;
      const final: IUserInfo = {
        username: user.displayName,
        email: user.email,
        avatar: user.photoURL,
        uid: user.uid,
        token: token,
      };
      resolve(final);
      Loading.hide();
    }
  });
}
export function twitter(): Promise<IUserInfo> {
  return new Promise(async (resolve, reject) => {
    Loading.show();
    const provider = new TwitterAuthProvider();
    const auth = getAuth();
    const result = await signInWithPopup(auth, provider).catch(
      async (error) => {
        if (error.code === AuthErrorCodes.NEED_CONFIRMATION) {
          const credential = TwitterAuthProvider.credentialFromError(error);
          const user = await handleAccountExistsError(
            auth,
            error.customData!.email as string,
            credential
          );

          if (user) {
            resolve(user);
          } else {
            Dialog.create({
              title: 'Error',
              message: 'Sign in Failed',
            });
          }
          Loading.hide();
          return;
        }
        Dialog.create({
          title: error.code,
          message: error.message,
        });
        reject(error);
        Loading.hide();
        return;
      }
    );
    if (result) {
      const credential = TwitterAuthProvider.credentialFromResult(result);
      const token = credential?.accessToken;
      const user = result.user;
      const final: IUserInfo = {
        username: user.displayName,
        email: user.email,
        avatar: user.photoURL,
        uid: user.uid,
        token: token,
      };
      resolve(final);
      Loading.hide();
    }
  });
}
export function signOut(): Promise<void> {
  return SignOut(getAuth());
}

export interface IUserInfo {
  googleId?: string | null;
  username?: string | null;
  email?: string | null;
  avatar?: string | null;
  birthday?: string | null;
  msliveId?: string | null;
  facebookId?: string | null;
  twitterId?: string | null;
  uid?: string | null;
  token?: string | null;
}
